package com.sna.snaapplication.service.Orekit;


import com.fasterxml.jackson.databind.ObjectMapper;

import com.sna.snaapplication.entity.model.OrekitData;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;

import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.TopocentricFrame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;

import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.text.ParseException;
import java.util.*;

@Service
public class SatelliteOrbitService2 {

    // Orekit 数据目录路径
    private static final String OREKIT_DATA_PATH = "D:\\springBoot\\Sna_develop\\src\\main\\resources\\static\\orekit-data-master";

    // 广州站的经纬度和海拔高度
    private static final double GUANGZHOU_LATITUDE = Math.toRadians(23.1291);
    private static final double GUANGZHOU_LONGITUDE = Math.toRadians(113.2644);
    private static final double GUANGZHOU_ALTITUDE = 10.0;

    /**
     * 配置 Orekit 数据目录
     */
    private void setupOrekitData(String orekitDataPath) throws OrekitException {
        File orekitData = new File(orekitDataPath);
        if (!orekitData.exists() || !orekitData.isDirectory()) {
            throw new OrekitException(null, "Orekit data directory not found at: " + orekitDataPath);
        }
        DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
        manager.addProvider(new DirectoryCrawler(orekitData));
    }

    public List<OrekitData> getOrbitData() {
        List<OrekitData> orbitDataList = new ArrayList<>();
        try {
            setupOrekitData(OREKIT_DATA_PATH);
            // 修改文件路径为新的 TXT 文件
            File j2000File = new File("D:\\springBoot\\Sna_develop\\src\\main\\resources\\static\\卫星1-J2000位置速度.txt");

            if (!j2000File.exists()) {
                throw new RuntimeException("错误：J2000位置速度文件不存在，路径=" + j2000File.getAbsolutePath());
            }
            try (BufferedReader reader = new BufferedReader(new FileReader(j2000File))) {
                // 跳过前两行：表头和分隔线
                String header1 = reader.readLine();
                String header2 = reader.readLine();
                System.out.println("DEBUG: J2000 Header1 = [" + header1 + "]");
                System.out.println("DEBUG: J2000 Header2 = [" + header2 + "]");
                String line;
                while ((line = reader.readLine()) != null) { //按行读

                    line = line.trim();
                    if (line.isEmpty()) {
                        continue;
                    }
                    // 按空格分隔
                    String[] tokens = line.split("\\s+");
                    if (tokens.length < 9) {
                        throw new RuntimeException("错误：J2000数据格式不正确，至少需要9列，line=" + line);
                    }
                    // tokens[0]为日期，tokens[1]为时间，tokens[2]为Elapsed Time（可忽略）
                    String dateStr = tokens[0] + " " + tokens[1]; // 例如 "2022-11-05 00:00:00.000000"
                    //字符串转日期
                    AbsoluteDate date = parseJ2000Date(dateStr);
                    // 假设 tokens[3]=x, [4]=y, [5]=z, [6]=vx, [7]=vy, [8]=vz
                    double x  = Double.parseDouble(tokens[3]); //字符串转Double类型
                    double y  = Double.parseDouble(tokens[4]);
                    double z  = Double.parseDouble(tokens[5]);
                    double vx = Double.parseDouble(tokens[6]);
                    double vy = Double.parseDouble(tokens[7]);
                    double vz = Double.parseDouble(tokens[8]);
                    OrekitData data = new OrekitData(date,x,y,z,vx,vy,vz);

                    orbitDataList.add(data);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("错误：解析J2000位置速度文件失败：" + e.getMessage(), e);
        }
        System.out.println("获取的数据为：");
        System.out.println(orbitDataList);
        return orbitDataList;
    }

    /**
     * 从 J2000位置速度(1).txt 读取数据，并转换为 CZML 格式的 JSON 字符串
     */
    public String getJ2000OrbitCZML2() {
        try {
            // 获取 TXT 文件解析得到的数据
            List<OrekitData> dataList = getOrbitData();
            if (dataList.isEmpty()) {
                return "[]";
            }
            // 以第一条数据的时间作为 epoch
            //第一条数据时间
            AbsoluteDate epochDate = dataList.get(0).getDate();
            //最后一条数据时间
            AbsoluteDate endDate = dataList.get(dataList.size() - 1).getDate();

            // 将 epoch 转换为字符串（去掉毫秒部分），加上 "Z" 标识 UTC
            String epochStr = epochDate.toString().replace(".000", "") ;
            String endStr = endDate.toString().replace(".000", "") ;
            System.out.println("epochStr:"+epochStr);
            System.out.println("endStr:"+endStr);
            String availability = epochStr + "/" + endStr;

            // 构造 CZML 中 position 的 cartesian 数组：[t0, x0, y0, z0, t1, x1, y1, z1, ...]
            List<Double> cartesian = new ArrayList<>();
            // 记录可见性信息
            List<Boolean> visibilityList = new ArrayList<>();

            // 定义地球形状
            BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                    Constants.WGS84_EARTH_FLATTENING,
                    FramesFactory.getITRF(IERSConventions.IERS_2010, true));
            GeodeticPoint guangzhouPoint = new GeodeticPoint(GUANGZHOU_LATITUDE, GUANGZHOU_LONGITUDE, GUANGZHOU_ALTITUDE);
            TopocentricFrame guangzhouFrame = new TopocentricFrame(earth, guangzhouPoint, "guangzhou");
            Frame inertialFrame = FramesFactory.getEME2000();

            for (OrekitData d : dataList) {
                //计算某个时间点相对于起始时间点的时间偏移量
                double offset = d.getDate().durationFrom(epochDate);
                cartesian.add(offset); //偏移量
                cartesian.add(d.getX());
                cartesian.add(d.getY());
                cartesian.add(d.getZ());

                // 计算卫星在惯性系下的位置
                PVCoordinates satellitePV = new PVCoordinates(new org.hipparchus.geometry.euclidean.threed.Vector3D(d.getX(), d.getY(), d.getZ()),
                        new org.hipparchus.geometry.euclidean.threed.Vector3D(d.getVx(), d.getVy(), d.getVz()));
                // 计算卫星在地面站坐标系下的位置
                org.hipparchus.geometry.euclidean.threed.Vector3D satellitePosInTopo = guangzhouFrame.getTransformTo(inertialFrame, d.getDate()).transformPosition(satellitePV.getPosition());
                // 判断卫星是否可见
                double elevation = guangzhouFrame.getElevation(satellitePosInTopo, inertialFrame, d.getDate());
                boolean isVisible = elevation > 0;
                visibilityList.add(isVisible);
            }

            // 构造 CZML 数据结构（使用 Map 形式）
            Map<String, Object> document = new HashMap<>();
            document.put("id", "document");
            document.put("name", "J2000 Orbit Document");
            document.put("version", "1.0");

            Map<String, Object> satellite = new HashMap<>();
            satellite.put("id", "j2000-satellite-1");
            satellite.put("name", "J2000 Satellite");
            satellite.put("availability", availability);

            Map<String, Object> position = new HashMap<>();
            position.put("epoch", epochStr);
            position.put("referenceFrame", "INERTIAL"); // 或 "FIXED" 取决于你的数据
            position.put("cartesian", cartesian);
            satellite.put("position", position);

            // 可选：定义卫星外观
            Map<String, Object> point = new HashMap<>();
            point.put("pixelSize", 8);
            Map<String, Object> color = new HashMap<>();
            color.put("rgba", Arrays.asList(255, 0, 0, 255));
            point.put("color", color);
            satellite.put("point", point);

            // 添加轨道路径属性
            Map<String, Object> path = new HashMap<>();
            path.put("show", true);
            path.put("width", 2);
            path.put("material", new HashMap<String, Object>() {{
                put("solidColor", new HashMap<String, Object>() {{
                    put("rgba", Arrays.asList(0, 0, 255, 128)); // 半透明蓝色轨道
                }});
            }});
            satellite.put("path", path);

            // 添加地面站信息到 CZML
            Map<String, Object> groundStation = new HashMap<>();
            groundStation.put("id", "guangzhou-ground-station");
            groundStation.put("name", "广州地面站");
            groundStation.put("availability", availability);

            // 计算地面站在惯性系下的位置
            PVCoordinates groundStationPV = guangzhouFrame.getPVCoordinates(epochDate, inertialFrame);
            List<Double> groundStationCartesian = Arrays.asList(
                    0.0, groundStationPV.getPosition().getX(), groundStationPV.getPosition().getY(), groundStationPV.getPosition().getZ()
            );

            Map<String, Object> groundStationPosition = new HashMap<>();
            groundStationPosition.put("epoch", epochStr);
            groundStationPosition.put("referenceFrame", "INERTIAL");
            groundStationPosition.put("cartesian", groundStationCartesian);
            groundStation.put("position", groundStationPosition);

            // 将地面站的经纬度和海拔高度添加到 CZML 数据中
            groundStation.put("latitude", Math.toDegrees(GUANGZHOU_LATITUDE));
            groundStation.put("longitude", Math.toDegrees(GUANGZHOU_LONGITUDE));
            groundStation.put("altitude", GUANGZHOU_ALTITUDE);

            // 定义地面站外观
            Map<String, Object> groundStationPoint = new HashMap<>();
            groundStationPoint.put("pixelSize", 8);
            Map<String, Object> groundStationColor = new HashMap<>();
            groundStationColor.put("rgba", Arrays.asList(0, 0, 255, 255));
            groundStationPoint.put("color", groundStationColor);
            groundStation.put("point", groundStationPoint);

            // 添加可见性信息到 CZML
            Map<String, Object> show = new HashMap<>();
            List<Object> intervals = new ArrayList<>();
            int startIndex = 0;

            for (int i = 1; i <= visibilityList.size(); i++) {
                if (i == visibilityList.size() || !Objects.equals(visibilityList.get(i), visibilityList.get(startIndex))) {
                    String start = epochDate.shiftedBy(dataList.get(startIndex).getDate().durationFrom(epochDate)).toString().replace(".000", "");
                    String end = i == visibilityList.size() ? endStr : epochDate.shiftedBy(dataList.get(i).getDate().durationFrom(epochDate)).toString().replace(".000", "");
                    System.out.println("start:"+start);
                    System.out.println("end:"+end);
                    Map<String, Object> interval = new HashMap<>();

                    interval.put("interval",start + "/" + end );
                    interval.put("boolean", visibilityList.get(startIndex));
                    intervals.add(interval);
                    startIndex = i;
                }
            }
            show.put("intervals", intervals);
            satellite.put("show", show);

            // 将 CZML 对象组合成数组
            List<Object> czml = new ArrayList<>();
            czml.add(document);
            czml.add(satellite);
            czml.add(groundStation);

            // 使用 Jackson 将 czml 转为 JSON 字符串
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(czml);
        } catch (Exception e) {
            throw new RuntimeException("错误：生成J2000 CZML失败，原因：" + e.getMessage(), e);
        }
    }

    /**
     * 辅助方法：解析 "yyyy-MM-dd HH:mm:ss.SSSSSS" 格式的日期字符串
     */
    private AbsoluteDate parseJ2000Date(String dateStr) throws ParseException {
        // 期望格式："2022-11-05 00:00:00.000000"
        String[] parts = dateStr.split(" ");
        if (parts.length < 2) {
            throw new ParseException("日期字符串格式错误：" + dateStr, 0);
        }
        String datePart = parts[0];
        String timePart = parts[1];

        String[] dateSplit = datePart.split("-");
        if (dateSplit.length < 3) {
            throw new ParseException("日期部分格式错误：" + datePart, 0);
        }
        int year  = Integer.parseInt(dateSplit[0]);
        int month = Integer.parseInt(dateSplit[1]);
        int day   = Integer.parseInt(dateSplit[2]);

        String[] timeSplit = timePart.split("\\.");
        if (timeSplit.length < 2) {
            throw new ParseException("时间部分格式错误：" + timePart, 0);
        }
        String hhmmss = timeSplit[0];  // "HH:mm:ss"
        String micro  = timeSplit[1];   // "SSSSSS"
        String[] hms = hhmmss.split(":");
        if (hms.length < 3) {
            throw new ParseException("时间格式错误：" + hhmmss, 0);
        }
        int hour   = Integer.parseInt(hms[0]);
        int minute = Integer.parseInt(hms[1]);
        int second = Integer.parseInt(hms[2]);
        return new AbsoluteDate(year, month, day, hour, minute, second, TimeScalesFactory.getUTC());
    }
}